import axios from "@/libs/axios";

import qs from "qs";
export const Global = typeof window !== "undefined" ? window : global;
export const formaters = {
  mobile: value => {
    return `${value.substr(0, 3)}-${value.substr(3, 4)}-${value.substr(7)}`;
  },
  price: value => {
    const p = parseFloat(value);

    if (!p) {
      return "0.00";
    }

    return p.toFixed(2);
  },
  playMount: value => {
    var temp = parseInt(value);

    if (!temp) {
      return 0;
    } else {
      if (temp < 10000 && temp > 0) {
        return temp;
      } else if (temp >= 10000) {
        return parseInt(temp / 10000) + "万";
      } else {
        return 0;
      }
    }
  },
  audioDuration: duration => {
    const minute = parseInt(duration / 60.0) || 0;
    const seconds =
      parseInt(
        (parseFloat(duration / 60.0) - parseInt(duration / 60.0)) * 60
      ) || 0;

    return (
      String(minute).padStart(2, "0") + ":" + String(seconds).padStart(2, "0")
    );
  }
};

export const parseQuery = () =>
  qs.parse(location.search, { ignoreQueryPrefix: true });

export const noop = () => {};

export const getViewPort = () => {
  const d = document.documentElement;
  const b = document.body;
  return {
    width: d.clientWidth || b.clientWidth,
    height: d.clientHeight || b.clientHeight
  };
};

export const getScroll = () => {
  let scrollTop = 0;
  let bodyScrollTop = 0;
  let documentScrollTop = 0;
  let scrollHeight = 0;
  let bodyScrollHeight = 0;
  let documentScrollHeight = 0;

  if (document.body) {
    bodyScrollHeight = document.body.scrollHeight;
    bodyScrollTop = document.body.scrollTop;
  }

  if (document.documentElement) {
    documentScrollHeight = document.documentElement.scrollHeight;
    documentScrollTop = document.documentElement.scrollTop;
  }

  scrollTop =
    bodyScrollTop - documentScrollTop > 0 ? bodyScrollTop : documentScrollTop;
  scrollHeight =
    bodyScrollHeight - documentScrollHeight > 0
      ? bodyScrollHeight
      : documentScrollHeight;

  return {
    top: scrollTop,
    height: scrollHeight
  };
};

function make_assign() {
  if (Object.assign) {
    return Object.assign;
  } else {
    return function shimAssign(obj) {
      for (var i = 1; i < arguments.length; i++) {
        each(Object(arguments[i]), function(val, key) {
          obj[key] = val;
        });
      }
      return obj;
    };
  }
}

export const assign = make_assign();

function make_create() {
  if (Object.create) {
    return function create(obj) {
      var assignArgsList = slice(arguments, 1);
      return assign.apply(this, [Object.create(obj)].concat(assignArgsList));
    };
  } else {
    function F() {} // eslint-disable-line no-inner-declarations
    return function create(obj) {
      var assignArgsList = slice(arguments, 1);
      F.prototype = obj;
      return assign.apply(this, [new F()].concat(assignArgsList));
    };
  }
}

export const create = make_create();

function make_trim() {
  if (String.prototype.trim) {
    return function trim(str) {
      return String.prototype.trim.call(str);
    };
  } else {
    return function trim(str) {
      return str.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, "");
    };
  }
}

export const trim = make_trim();

export const bind = (obj, fn) => {
  return function() {
    return fn.apply(obj, Array.prototype.slice.call(arguments, 0));
  };
};

export const slice = (arr, index) => {
  return Array.prototype.slice.call(arr, index || 0);
};

export const each = (obj, fn) => {
  pluck(obj, function(val, key) {
    fn(val, key);
    return false;
  });
};

export const map = (obj, fn) => {
  var res = isList(obj) ? [] : {};
  pluck(obj, function(v, k) {
    res[k] = fn(v, k);
    return false;
  });
  return res;
};

export const pluck = (obj, fn) => {
  if (isList(obj)) {
    for (var i = 0; i < obj.length; i++) {
      if (fn(obj[i], i)) {
        return obj[i];
      }
    }
  } else {
    for (var key in obj) {
      if (obj.hasOwnProperty(key)) {
        if (fn(obj[key], key)) {
          return obj[key];
        }
      }
    }
  }
};

export const isList = val => {
  return (
    val != null && typeof val != "function" && typeof val.length == "number"
  );
};

export const isFunction = val => {
  return val && {}.toString.call(val) === "[object Function]";
};

export const isObject = val => {
  return val && {}.toString.call(val) === "[object Object]";
};

export const isWechat = /micromessenger/i.test(navigator.userAgent);

export const getCurrentUrl = (query, hash = "") => {
  const { origin, pathname } = window.location;

  return `${origin}${pathname}${qs.stringify(query, {
    addQueryPrefix: true
  })}${hash}`;
};
export const objToStr = obj => {
  if (!isObject(obj)) {
    return obj;
  } else {
    let temp = "";
    for (let item in obj) {
      temp += item + ":" + obj[item] + ",";
    }
    return "{" + temp.substring(0, temp.length - 1) + "}";
  }
};

export const getUrl = (
  path = window.location.pathname,
  query = {},
  hash = ""
) => {
  return `${path}${qs.stringify(query, { addQueryPrefix: true })}${hash}`;
};

export const getFullPath = path => {
  if (path.indexOf("http://") === 0 || path.indexOf("https://") === 0) {
    return path;
  }

  if (path.indexOf("//") === 0) {
    return `${location.protocol}${path}`;
  }

  if (path.indexOf("/") === 0) {
    return `${location.origin}${path}`;
  }

  return `${location.origin}/${path}`;
};

const hiddenProperty =
  "hidden" in document
    ? "hidden"
    : "webkitHidden" in document
    ? "webkitHidden"
    : "mozHidden" in document
    ? "mozHidden"
    : '';
export const visibilityChange = {
  inited: false,
  visibilityChangeEvent: hiddenProperty.replace(/hidden/i, "visibilitychange"),
  on(showCallback, hideCallback) {
    if (this.inited) {
      return;
    }

    this.inited = true;
    this.onVisibilityChange = () => {
      if (!document[hiddenProperty]) {
        showCallback && showCallback();
      } else {
        hideCallback && hideCallback();
      }
    };
    document.addEventListener(
      this.visibilityChangeEvent,
      this.onVisibilityChange
    );
  },
  off() {
    if (!this.inited) {
      return;
    }

    this.inited = false;

    document.removeEventListener(
      this.visibilityChangeEvent,
      this.onVisibilityChange
    );
  }
};

// scrollTop animation
export const scrollTop = (el, from = 0, to, duration = 500, endCallback) => {
  if (!window.requestAnimationFrame) {
    window.requestAnimationFrame =
      window.webkitRequestAnimationFrame ||
      window.mozRequestAnimationFrame ||
      window.msRequestAnimationFrame ||
      function(callback) {
        return window.setTimeout(callback, 1000 / 60);
      };
  }
  const difference = Math.abs(from - to);
  const step = Math.ceil((difference / duration) * 50);

  const scroll = (start, end, step) => {
    if (start === end) {
      endCallback && endCallback();
      return;
    }

    let d = start + step > end ? end : start + step;
    if (start > end) {
      d = start - step < end ? end : start - step;
    }

    if (el === window) {
      window.scrollTo(d, d);
    } else {
      el.scrollTop = d;
    }
    window.requestAnimationFrame(() => scroll(d, end, step));
  };
  scroll(from, to, step);
};

export const parseUrl = str => {
  const d = document.createElement("a");
  d.href = str;

  return d;
};

export const parseSearch = str => {
  const url = parseUrl(str);

  return qs.parse(url.search, { ignoreQueryPrefix: true });
};

const Utils = {
  isChinaMobile: (mobile, code) => {
    const reg = /^(13[0-9]|15[012356789]|17[01235678]|18[0-9]|14[579]|19[189]|166)[0-9]{8}$/;

    if (!mobile) {
      return false;
    }

    // 如果有传区号，并且区号不等于 +86 同时不等于 86 则认为是非中国区手机号，直接返回true
    if (code && String(code) !== "+86" && String(code) !== "86") {
      return true;
    }

    if (reg.test(mobile)) {
      return true;
    }

    return false;
  },
  query: () => {
    const matchHtmlRegExp = /["'&<>]/g;
    const querys = {};
    const query = window.location.search.substring(1);
    const vars = query.split("&");

    vars.forEach(v => {
      const pair = v.split("=");
      if (pair[0]) {
        querys[pair[0]] = decodeURIComponent(pair[1]).replace(
          matchHtmlRegExp,
          ""
        );
      }
    });

    return querys;
  },
  viewport: () => ({
    width:
      window.innerWidth ||
      document.documentElement.clientWidth ||
      document.body.clientWidth,
    height:
      window.innerHeight ||
      document.documentElement.clientHeight ||
      document.body.clientHeight
  }),
  rem: px => {
    const viewport = Utils.viewport();
    const ww = viewport.width;
    let scale = ww / 375;

    if (ww >= 768) {
      scale = 768 / 375;
    }

    return px * scale;
  },
  setWeixinTitle: title => {
    const { body } = document;
    document.title = title; // hack在微信等webview中无法修改document.title的情况
    const $iframe = document.createElement("iframe");
    $iframe.src = "/favicon.ico";
    $iframe.style.display = "none";
    $iframe.onload = () => {
      setTimeout(() => {
        $iframe.onload = null;
        body.removeChild($iframe);
      }, 0);
    };
    body.appendChild($iframe);
  },
  genTypes: (model, group) =>
    Object.keys(model).reduce((prev, key) => {
      prev[key] = `${group}.${key}`;
      return prev;
    }, {}),
  genState: (model, group) =>
    Object.keys(model).reduce((prev, key) => {
      prev[`${group}.${key}`] = model[key];

      return prev;
    }, {}),
  genGetters: types =>
    Object.values(types).reduce((prev, value) => {
      prev[value] = state => state[value];
      return prev;
    }, {}),
  genMutations: types =>
    Object.values(types).reduce((prev, value) => {
      prev[value] = (state, payload) => {
        state[value] = payload;
      };
      return prev;
    }, {}),
  gen: (gens, apis, key, option) =>
    gens[key] && gens[key](apis[key], option[key]),
  genAction: (key, types, model) => (paramsFn, options = {}) => (
    store,
    payload
  ) => {
    let params = paramsFn(store, payload);

    if (typeof params === "string") {
      params = {
        url: params,
        method: "post",
        params: payload,
        data: payload || {}
      };
    }
    store.commit(types[key], { loading: true });

    return axios
      .request(params)
      .then(res => {
        let data = res.data;
        if (typeof options.transform === "function") {
          data = options.transform(res, store);
        }

        store.commit(types[key], data);
        return res;
      })
      .catch(err => {
        store.commit(types[key], model[key]);
        throw err;
      });
  },
  genActions: (types, apis, gens, options) =>
    Object.keys(types).reduce((prev, key) => {
      prev[types[key]] = Utils.gen(gens, apis, key, options);
      return prev;
    }, {}),
  listTransform: t => {
    const { pageData, ...restData } = t.data;

    return {
      ...restData,
      list: pageData || []
    };
  },
  buildSZM: (objArr, keys) =>
    objArr.map(obj => keys.map(key => obj[key]).join("|")).join("@"),
  searchSZM: (szm, keys, key) => {
    let arr = [];
    let result = [];

    key = key.trim();

    result = [];
    arr = ["@([^@]*)?", key, "([^@]*)"];

    szm.replace(new RegExp(arr.join(""), "g"), str => {
      const varr = str.slice(1).split("|");
      const obj = {};
      keys.forEach((k, i) => {
        obj[k] = varr[i];
      });

      result.push(obj);

      return result;
    });

    return result;
  },
  padLeftZero(str) {
    return ("00" + str).substr(str.length);
  },
  formatDate(date, fmt) {
    if (/(y+)/.test(fmt)) {
      fmt = fmt.replace(
        RegExp.$1,
        (date.getFullYear() + "").substr(4 - RegExp.$1.length)
      );
    }
    let o = {
      "M+": date.getMonth() + 1,
      "d+": date.getDate(),
      "h+": date.getHours(),
      "m+": date.getMinutes(),
      "s+": date.getSeconds()
    };
    for (let k in o) {
      if (new RegExp(`(${k})`).test(fmt)) {
        let str = o[k] + "";
        fmt = fmt.replace(
          RegExp.$1,
          RegExp.$1.length === 1 ? str : this.padLeftZero(str)
        );
      }
    }
    return fmt;
  }
};

export default Utils;
